# stoker_commands: mapping structure for Stoker commands
#
# Author:   Mike Murphy (mamurph@cs.clemson.edu)
# Revision: 9 September 2008
#
#   Copyright 2007-2008 Clemson University
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
#
# This material is based upon work supported under a National Science
# Foundation Graduate Research Fellowship. Any opinions, findings,
# conclusions or recommendations expressed in this publication are those of
# the author(s) and do not necessarily reflect the views of the National
# Science Foundation.

# Command definition dictionary
#
# The format of this structure is an outer dictionary mapping literal command
# names to an inner dictionary of command option/argument metadata. The inner
# dictionaries have the format:
#
# SHORT_OPTIONS : <getopt string containing short option control chars>,
# LONG_OPTIONS : <getopt string containing long option controls>,
# ARGUMENTS : <list of strings describing command arguments>,
# MIN_ARGS : <minimum number of args required for this command>,
# MAX_ARGS : <maximum number of args allowed for this command>
#
# If the command accepts no options, an empty string is used for
# SHORT_OPTIONS, while an empty list is used for LONG_OPTIONS. If a
# command will accept no arguments, both MIN_ARGS and MAX_ARGS must be
# zero, AND the ARGUMENTS list should be empty. The ARGUMENTS list
# MUST NOT be empty if the command supports one or more arguments.
#
# In the event that MIN_ARGS > 0, and MAX_ARGS > MIN_ARGS, the first
# MIN_ARGS arguments to the command will be treated as required (the Stoker
# core logic will check the argument count and error out as appropriate),
# while remaining arguments will be optional. If MIN_ARGS is zero, then all
# arguments are optional. To permit an unbounded number of arguments (e.g.
# a parameter list to be passed to an external command), set MAX_ARGS to -1.
#

from stoker_defines import SHORT_OPTIONS, LONG_OPTIONS, ARGUMENTS, \
      MIN_ARGS, MAX_ARGS, RESOLVER_RULE, CMD_CLASS, RESOLVE_TO_DEFAULT, \
      RESOLVE_TO_MAC

import stoker_exec, stoker_copy, stoker_ping, stoker_do, stoker_py, \
         stoker_wake

STOKER_COMMAND_MAP = {
   'exec' : {
      SHORT_OPTIONS : 's',
      LONG_OPTIONS : ['script'],
      ARGUMENTS : ['command-or-script'],
      MIN_ARGS : 1,
      MAX_ARGS : -1,
      RESOLVER_RULE : RESOLVE_TO_DEFAULT,
      CMD_CLASS : stoker_exec.ExecCommand,
   },

   'copy' : {
      SHORT_OPTIONS : 'pr',
      LONG_OPTIONS : ['preserve-mode', 'recursive'],
      ARGUMENTS : ['sources(s)', 'destination'],
      MIN_ARGS : 2,
      MAX_ARGS : -1,
      RESOLVER_RULE : RESOLVE_TO_DEFAULT,
      CMD_CLASS : stoker_copy.CopyCommand,
   },

   'ping' : {
      SHORT_OPTIONS : 'c:W:',
      LONG_OPTIONS : [],
      ARGUMENTS : [],
      MIN_ARGS : 0,
      MAX_ARGS : 0,
      RESOLVER_RULE : RESOLVE_TO_DEFAULT,
      CMD_CLASS : stoker_ping.PingCommand,
   },

   'do' : {
      SHORT_OPTIONS : '',
      LONG_OPTIONS : [],
      ARGUMENTS : ['action', 'arg1', 'args'],
      MIN_ARGS : 1,
      MAX_ARGS : -1,
      RESOLVER_RULE : RESOLVE_TO_DEFAULT,
      CMD_CLASS : stoker_do.DoCommand,
   },

   'py' : {
      SHORT_OPTIONS : '',
      LONG_OPTIONS : [],
      ARGUMENTS : ['python-file', 'args'],
      MIN_ARGS : 1,
      MAX_ARGS : -1,
      RESOLVER_RULE : RESOLVE_TO_DEFAULT,
      CMD_CLASS : stoker_py.PyCommand,
   },

   'wake' : {
      SHORT_OPTIONS : 'b:p:t:',
      LONG_OPTIONS : [ 'broadcast=', 'port=', 'tries=' ],
      ARGUMENTS : [],
      MIN_ARGS : 0,
      MAX_ARGS : 0,
      RESOLVER_RULE : RESOLVE_TO_MAC,
      CMD_CLASS : stoker_wake.WakeCommand,
   },
}

def pr_synopsis(cmd):
   synstr = cmd + ' '
   shortopt = STOKER_COMMAND_MAP[cmd][SHORT_OPTIONS]
   longopt = STOKER_COMMAND_MAP[cmd][LONG_OPTIONS]
   argdesc = STOKER_COMMAND_MAP[cmd][ARGUMENTS]
   argreq = STOKER_COMMAND_MAP[cmd][MIN_ARGS]
   argmax = STOKER_COMMAND_MAP[cmd][MAX_ARGS]
   #
   if len(shortopt) > 0 or len(longopt) > 0:
      synstr += '[ '
      for opt in shortopt:
         if opt != ':':
            synstr += '-' + opt + ' '
         else:
            synstr += '<?> '
      for lopt in longopt:
         synstr += '--' + lopt
         if lopt.endswith('='):
            synstr += '<?>'
         synstr += ' '
      synstr += '] '
   count = 0
   for arg in argdesc:
      if count < argreq:
         synstr += '<' + arg + '> '
      else:
         synstr += '[' + arg + '] '
      count += 1
   print synstr
